#include "string.h"

const size_t ly::string::npos = -1;

ly::string::string(const char* str)
	:_size(strlen(str))
	, _capacity(_size)
{
	_str = new char[_capacity + 1];
	strcpy(_str, str);
}

ly::string::string(const string& s)
{
	if (_str != s._str)
	{
		char* tmp = new char[s._capacity + 1];
		//delete[] _str;

		strcpy(tmp, s._str);
		_str = tmp;
		_size = s._size;
		_capacity = s._capacity;
	}
}

const char* ly::string::c_str()
{
	return _str;
}

ly::string::~string()
{
	delete[] _str;
	_capacity = _size = 0;
}

ly::string& ly::string::operator=(const string& s)
{
	if (this->_str != s._str)
	{
		char* tmp = new char[s._capacity + 1];
		delete[] _str;

		strcpy(tmp, s._str);
		_str = tmp;
		_size = s._size;
		_capacity = s._capacity;
	}

	return *this;
}

ly::string::iterator ly::string::begin()
{
	return _str;
}

ly::string::iterator ly::string::end()
{
	return _str + _size;
}

ly::string::iterator ly::string::begin() const
{
	return _str;
}

ly::string::iterator ly::string::end() const
{
	return _str + _size;
}

void ly::string::push_back(char c)
{
	if (_size == _capacity)
	{
		reserve(_capacity*2);
	}

	_str[_size++] = c;
	_str[_size] = '\0';
}

void ly::string::reserve(size_t n)
{
	if (n > _capacity)
	{
		char* tmp = new char[n + 1];
		strcpy(tmp, _str);
		delete[] _str;

		_str = tmp;
		_capacity = n;
	}
}

size_t ly::string::size() const
{
	return _size;
}

size_t ly::string::capacity() const
{
	return _capacity;
}

bool ly::string::empty() const
{
	return (_size == 0);
}

void ly::string::resize(size_t n, char c)
{
	if (n <= _size)
	{
		_str[n] = '\0';
		_size = n;
	}
	else
	{
		reserve(n);
		while (_size < n)
		{
			_str[_size++] = c;
		}
		_str[_size] = '\0';
	}
}

char& ly::string::operator[](size_t index)
{
	return _str[index];
}

const char& ly::string::operator[](size_t index) const
{
	return _str[index];
}

ly::string& ly::string::operator+=(char c)
{
	push_back(c);

	return *this;
}

void ly::string::append(const char* str)
{
	size_t len = strlen(str);
	reserve(_size + len);

	strcpy(_str + _size, str);
	_size = strlen(_str);
}


ly::string& ly::string::operator+=(const char* str)
{
	append(str);

	return *this;
}

void ly::string::clear()
{
	_size = 0;
	_str[_size] = '\0';
}

//void ly::string::swap(ly::string& s)
//{
//	ly::string tmp(s);
//	s._str = _str;
//	s._capacity = _capacity;
//	s._size = _size;
//
//	_str = tmp._str;
//	_capacity = tmp._capacity;
//	_size = tmp._size;
//}

void ly::string::swap(ly::string& s)
{
	std::swap(_str, s._str);
	std::swap(_capacity, s._capacity);
	std::swap(_size, s._size);
}

bool ly::string::operator<(const ly::string& s) const
{
	return (strcmp(_str, s._str) < 0);
}

bool ly::string::operator<=(const ly::string& s) const
{
	return (strcmp(_str, s._str) <= 0);
}
bool ly::string::operator>(const ly::string& s) const
{
	return !(*this <= s);
}
bool ly::string::operator>=(const ly::string& s) const
{
	return !(*this < s);
}
bool ly::string::operator==(const ly::string& s) const
{
	return (strcmp(_str, s._str) == 0);
}
bool ly::string::operator!=(const ly::string& s) const
{
	return !(*this == s);
}

size_t ly::string::find(char c, size_t pos) const
{
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == c)
		{
			return i;
		}
	}

	return npos;
}

size_t ly::string::find(const char* s, size_t pos) const
{
	const char* tmp = strstr(_str + pos, s);

	return tmp == nullptr ? npos : tmp - _str;

	//return (strstr(_str + pos, s) != nullptr) ? strstr(_str + pos, s) - _str : npos;
}

ly::string& ly::string::insert(size_t pos, char c)
{
	assert(pos <= _size);

	reserve(_size + 1);
	size_t end = _size + 1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		end--;
	}
	_str[pos] = c;
	_size++;

	return *this;
}

ly::string& ly::string::insert(size_t pos, const char* str)
{
	assert(pos <= _size);

	size_t len = strlen(str);
	reserve(_size + len);

	size_t end = _size + 1;
	while(end > pos)
	{
		_str[end + len - 1] = _str[end - 1];
		end--;
	}

	for (size_t i = 0; i < len; i++)
	{
		_str[pos + i] = str[i];
	}
	_size += len;

	return *this;
}

ly::string& ly::string::erase(size_t pos, size_t len)
{
	assert(pos < _size);

	if (len == pos || len > _size - pos + 1)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		for (size_t i = 0; i < _size - pos - len + 1; i++)
		{
			_str[pos + i] = _str[pos + len + i];
		}
		_size -= len;
	}

	return *this;
}

ostream& ly::operator<<(ostream& _cout, const ly::string& s)
{
	ly::string::const_iterator  it = s.begin();

	while (it != s.end())
	{
		_cout << *it;
		it++;
	}

	return _cout;
}

istream& ly::operator>>(istream& _cin, ly::string& s)
{
	s.clear();

	char buff[129] = { 0 };
	size_t i = 0;
	
	char ch;
	ch = _cin.get();
	while (ch != ' ' && ch != '\n')
	{
		buff[i++] = ch;
		ch = _cin.get();

		if (i == 128)
		{
			buff[i] = '\0';
			s += buff;
			i = 0;
		}
	}

	if (i != 0)
	{
		buff[i] = '\0';
		s += buff;
	}

	return _cin;
}
